package cn.elead.chaos.core.util;

import java.lang.management.ManagementFactory;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;

/**
 * 
 * jdk8时间工具类jdk8时间工具类
 * 
 * @author luopeng
 *
 */
public class DateUtil extends cn.hutool.core.date.DateUtil {

	public static final int SECONDS_PER_MINUTE = 60;

	public static final int MINUTES_PER_HOUR = 60;

	public static final int HOURS_PER_DAY = 24;

	public static final int SECONDS_PER_DAY = (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);

	public static final long DAY_MILLISECONDS = SECONDS_PER_DAY * 1000L;

	/**
	 * 当前时间，格式
	 *
	 * @return 当前时间的标准形式字符串
	 */
	public static String now(String format) {
		return format(new DateTime(), format);
	}

	/**
	 * LocalDateTime 转 自定义格式string 默认:yyyy-MM-dd hh:mm:ss
	 * 
	 * @param localDateTime
	 * @return
	 */
	public static String formatLocalDateTimeToString(LocalDateTime localDateTime) {
		return formatLocalDateTimeToString(localDateTime, DatePattern.NORM_DATETIME_PATTERN);
	}

	/**
	 * LocalDateTime 转 自定义格式string
	 *
	 * @param localDateTime
	 * @param format        例：yyyy-MM-dd hh:mm:ss
	 * @return
	 */
	public static String formatLocalDateTimeToString(LocalDateTime localDateTime, String format) {
		try {
			DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
			return localDateTime.format(formatter);
		} catch (DateTimeParseException e) {
		}
		return null;
	}

	/**
	 * string 转 LocalDateTime
	 *
	 * @param dateStr 例："2019-12-19 01:00:00"
	 * @return
	 */
	public static LocalDateTime stringToLocalDateTime(String dateStr) {
		return stringToLocalDateTime(dateStr, DatePattern.NORM_DATETIME_PATTERN);
	}

	/**
	 * string 转 LocalDateTime
	 *
	 * @param dateStr 例："2019-12-19 01:00:00"
	 * @param format  例："yyyy-MM-dd HH:mm:ss"
	 * @return
	 */
	public static LocalDateTime stringToLocalDateTime(String dateStr, String format) {
		try {
			DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
			return LocalDateTime.parse(dateStr, formatter);
		} catch (DateTimeParseException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * LocalDate 转 自定义格式string 默认:yyyy-MM-dd
	 * 
	 * @param LocalDate
	 * @return
	 */
	public static String formatLocalDateToString(LocalDate localDate) {
		return formatLocalDateToString(localDate, DatePattern.NORM_DATE_PATTERN);
	}

	/**
	 * LocalDate 转 自定义格式string
	 *
	 * @param LocalDate
	 * @param format    例：yyyy-MM-dd
	 * @return
	 */
	public static String formatLocalDateToString(LocalDate localDate, String format) {
		try {
			DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
			return localDate.format(formatter);
		} catch (DateTimeParseException e) {
		}
		return null;
	}

	/**
	 * string 转 LocalDateTime
	 *
	 * @param dateStr 例："2019-12-19"
	 * @return
	 */
	public static LocalDate stringToLocalDate(String dateStr) {
		return stringToLocalDate(dateStr, DatePattern.NORM_DATETIME_PATTERN);
	}

	/**
	 * string 转 LocalDate
	 *
	 * @param dateStr 例："2019-12-19"
	 * @param format  例："yyyy-MM-dd"
	 * @return
	 */
	public static LocalDate stringToLocalDate(String dateStr, String format) {
		try {
			DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
			return LocalDate.parse(dateStr, formatter);
		} catch (DateTimeParseException e) {
		}
		return null;
	}

	/**
	 * 获取服务器启动时间
	 */
	public static Date getServerStartDate() {
		long time = ManagementFactory.getRuntimeMXBean().getStartTime();
		return new Date(time);
	}

	/**
	 * 计算两个时间差
	 */
	public static String getDatePoor(Date endDate, Date nowDate) {
		long nd = 1000 * 24 * 60 * 60;
		long nh = 1000 * 60 * 60;
		long nm = 1000 * 60;
		// long ns = 1000;
		// 获得两个时间的毫秒时间差异
		long diff = endDate.getTime() - nowDate.getTime();
		// 计算差多少天
		long day = diff / nd;
		// 计算差多少小时
		long hour = diff % nd / nh;
		// 计算差多少分钟
		long min = diff % nd % nh / nm;
		// 计算差多少秒//输出结果
		// long sec = diff % nd % nh % nm / ns;
		return day + "天" + hour + "小时" + min + "分钟";
	}

	/**
	 * Given an Excel date with using 1900 date windowing, and converts it to a java.util.Date.
	 * 
	 * Excel Dates and Times are stored without any timezone information. If you know (through other means) that your
	 * file uses a different TimeZone to the system default, you can use this version of the getJavaDate() method to
	 * handle it.
	 * 
	 * @param date The Excel date.
	 * @param tz   The TimeZone to evaluate the date in
	 * @return Java representation of the date, or null if date is not a valid Excel date
	 */
	public static Date getJavaDate(double date, TimeZone tz) {
		return getJavaDate(date, false, tz, false);
	}

	/**
	 * Given an Excel date with using 1900 date windowing, and converts it to a java.util.Date.
	 *
	 * NOTE: If the default <code>TimeZone</code> in Java uses Daylight Saving Time then the conversion back to an Excel
	 * date may not give the same value, that is the comparison
	 * <CODE>excelDate == getExcelDate(getJavaDate(excelDate,false))</CODE> is not always true. For example if default
	 * timezone is <code>Europe/Copenhagen</code>, on 2004-03-28 the minute after 01:59 CET is 03:00 CEST, if the excel
	 * date represents a time between 02:00 and 03:00 then it is converted to past 03:00 summer time
	 *
	 * @param date The Excel date.
	 * @return Java representation of the date, or null if date is not a valid Excel date
	 * @see java.util.TimeZone
	 */
	public static Date getJavaDate(double date) {
		return getJavaDate(date, false, null, false);
	}

	/**
	 * Given an Excel date with either 1900 or 1904 date windowing, converts it to a java.util.Date.
	 * 
	 * Excel Dates and Times are stored without any timezone information. If you know (through other means) that your
	 * file uses a different TimeZone to the system default, you can use this version of the getJavaDate() method to
	 * handle it.
	 * 
	 * @param date             The Excel date.
	 * @param tz               The TimeZone to evaluate the date in
	 * @param use1904windowing true if date uses 1904 windowing, or false if using 1900 date windowing.
	 * @return Java representation of the date, or null if date is not a valid Excel date
	 */
	public static Date getJavaDate(double date, boolean use1904windowing, TimeZone tz) {
		return getJavaDate(date, use1904windowing, tz, false);
	}

	/**
	 * Given an Excel date with either 1900 or 1904 date windowing, converts it to a java.util.Date.
	 * 
	 * Excel Dates and Times are stored without any timezone information. If you know (through other means) that your
	 * file uses a different TimeZone to the system default, you can use this version of the getJavaDate() method to
	 * handle it.
	 * 
	 * @param date             The Excel date.
	 * @param tz               The TimeZone to evaluate the date in
	 * @param use1904windowing true if date uses 1904 windowing, or false if using 1900 date windowing.
	 * @param roundSeconds     round to closest second
	 * @return Java representation of the date, or null if date is not a valid Excel date
	 */
	public static Date getJavaDate(double date, boolean use1904windowing, TimeZone tz, boolean roundSeconds) {
		Calendar calendar = getJavaCalendar(date, use1904windowing, tz, roundSeconds);
		return calendar == null ? null : calendar.getTime();
	}

	/**
	 * Given an Excel date with either 1900 or 1904 date windowing, converts it to a java.util.Date.
	 *
	 * NOTE: If the default <code>TimeZone</code> in Java uses Daylight Saving Time then the conversion back to an Excel
	 * date may not give the same value, that is the comparison
	 * <CODE>excelDate == getExcelDate(getJavaDate(excelDate,false))</CODE> is not always true. For example if default
	 * timezone is <code>Europe/Copenhagen</code>, on 2004-03-28 the minute after 01:59 CET is 03:00 CEST, if the excel
	 * date represents a time between 02:00 and 03:00 then it is converted to past 03:00 summer time
	 *
	 * @param date             The Excel date.
	 * @param use1904windowing true if date uses 1904 windowing, or false if using 1900 date windowing.
	 * @return Java representation of the date, or null if date is not a valid Excel date
	 * @see java.util.TimeZone
	 */
	public static Date getJavaDate(double date, boolean use1904windowing) {
		return getJavaDate(date, use1904windowing, null, false);
	}

	/**
	 * Get EXCEL date as Java Calendar (with default time zone). This is like {@link #getJavaDate(double)} but returns a
	 * Calendar object.
	 * 
	 * @param date The Excel date.
	 * @return Java representation of the date, or null if date is not a valid Excel date
	 */
	public static Calendar getJavaCalendar(double date) {
		return getJavaCalendar(date, false, (TimeZone) null, false);
	}

	/**
	 * Get EXCEL date as Java Calendar (with default time zone). This is like {@link #getJavaDate(double, boolean)} but
	 * returns a Calendar object.
	 * 
	 * @param date             The Excel date.
	 * @param use1904windowing true if date uses 1904 windowing, or false if using 1900 date windowing.
	 * @return Java representation of the date, or null if date is not a valid Excel date
	 */
	public static Calendar getJavaCalendar(double date, boolean use1904windowing) {
		return getJavaCalendar(date, use1904windowing, (TimeZone) null, false);
	}

	/**
	 * Get EXCEL date as Java Calendar with UTC time zone. This is similar to {@link #getJavaDate(double, boolean)} but
	 * returns a Calendar object that has UTC as time zone, so no daylight saving hassle.
	 * 
	 * @param date             The Excel date.
	 * @param use1904windowing true if date uses 1904 windowing, or false if using 1900 date windowing.
	 * @return Java representation of the date in UTC, or null if date is not a valid Excel date
	 */
	public static Calendar getJavaCalendarUTC(double date, boolean use1904windowing) {
		return getJavaCalendar(date, use1904windowing, LocaleUtil.TIMEZONE_UTC, false);
	}

	/**
	 * Get EXCEL date as Java Calendar with given time zone.
	 * 
	 * @param date             The Excel date.
	 * @param use1904windowing true if date uses 1904 windowing, or false if using 1900 date windowing.
	 * @param timeZone         The TimeZone to evaluate the date in
	 * @return Java representation of the date, or null if date is not a valid Excel date
	 */
	public static Calendar getJavaCalendar(double date, boolean use1904windowing, TimeZone timeZone) {
		return getJavaCalendar(date, use1904windowing, timeZone, false);
	}

	/**
	 * Get EXCEL date as Java Calendar with given time zone.
	 * 
	 * @param date             The Excel date.
	 * @param use1904windowing true if date uses 1904 windowing, or false if using 1900 date windowing.
	 * @param timeZone         The TimeZone to evaluate the date in
	 * @param roundSeconds     round to closest second
	 * @return Java representation of the date, or null if date is not a valid Excel date
	 */
	public static Calendar getJavaCalendar(double date, boolean use1904windowing, TimeZone timeZone,
			boolean roundSeconds) {
		if (!isValidExcelDate(date)) {
			return null;
		}
		int wholeDays = (int) Math.floor(date);
		int millisecondsInDay = (int) ((date - wholeDays) * DAY_MILLISECONDS + 0.5);
		Calendar calendar;
		if (timeZone != null) {
			calendar = LocaleUtil.getLocaleCalendar(timeZone);
		} else {
			calendar = LocaleUtil.getLocaleCalendar(); // using default time-zone
		}
		setCalendar(calendar, wholeDays, millisecondsInDay, use1904windowing, roundSeconds);
		return calendar;
	}

	/**
	 * Given a double, checks if it is a valid Excel date.
	 *
	 * @return true if valid
	 * @param value the double value
	 */

	public static boolean isValidExcelDate(double value) {
		return (value > -Double.MIN_VALUE);
	}

	public static void setCalendar(Calendar calendar, int wholeDays, int millisecondsInDay, boolean use1904windowing,
			boolean roundSeconds) {
		int startYear = 1900;
		int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't
		if (use1904windowing) {
			startYear = 1904;
			dayAdjust = 1; // 1904 date windowing uses 1/2/1904 as the first day
		} else if (wholeDays < 61) {
			// Date is prior to 3/1/1900, so adjust because Excel thinks 2/29/1900 exists
			// If Excel date == 2/29/1900, will become 3/1/1900 in Java representation
			dayAdjust = 0;
		}
		calendar.set(startYear, 0, wholeDays + dayAdjust, 0, 0, 0);
		calendar.set(Calendar.MILLISECOND, millisecondsInDay);
		if (calendar.get(Calendar.MILLISECOND) == 0) {
			calendar.clear(Calendar.MILLISECOND);
		}
		if (roundSeconds) {
			calendar.add(Calendar.MILLISECOND, 500);
			calendar.clear(Calendar.MILLISECOND);
		}
	}
}
